﻿using Labthink.PCSoft.UniversalHost4.Utility;
using System;
using System.ComponentModel;
using System.IO;
using System.Media;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Labthink.PCSoft.UniversalHost4.UserControls
{
    public partial class IpMaskedTextBox
    {
        public TextBox FirstBox => firstBox;
        public TextBox SecondBox => secondBox;
        public TextBox ThirdBox => thirdBox;
        public TextBox FourthBox => fourthBox;

        public bool IsReadOnly {
            set
            {
                firstBox.IsReadOnly = value;
                secondBox.IsReadOnly = value;
                thirdBox.IsReadOnly = value;
                fourthBox.IsReadOnly = value;
            }
        }

        private readonly string ErrorMessage;

        public IpMaskedTextBox()
        {
            InitializeComponent();

            if (DesignerProperties.GetIsInDesignMode(this))
                return;

            var lang = SystemInfo.GetCurrentLocale();
            lang = lang.Replace("-", "");
            string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var langRD = Composer<ResourceDictionary>.GetLanguages(path, lang);
            Resources.MergedDictionaries.Add(langRD);
            ErrorMessage = langRD.GetLanguageValue("FormatError");
        }

        public IpMaskedTextBox(byte[] bytesToFill)
        {
            InitializeComponent();

            firstBox.Text = Convert.ToString(bytesToFill[0]);
            secondBox.Text = Convert.ToString(bytesToFill[1]);
            thirdBox.Text = Convert.ToString(bytesToFill[2]);
            fourthBox.Text = Convert.ToString(bytesToFill[3]);
        }

        //public string Text => string.Join(".", firstBox.Text, secondBox.Text, thirdBox.Text, fourthBox.Text);
        public string Text {
            get
            {
               var ip = string.Join(".", firstBox.Text, secondBox.Text, thirdBox.Text, fourthBox.Text);
                if (ip == "...") ip = "0.0.0.0";
                return ip;
            }
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    firstBox.Text = string.Empty;
                    secondBox.Text = string.Empty;
                    thirdBox.Text = string.Empty;
                    fourthBox.Text = string.Empty;
                    return;
                }
                var strs = value.Split('.');
                if(strs.Length <4) return;
                firstBox.Text = strs[0];
                secondBox.Text = strs[1];
                thirdBox.Text = strs[2];
                fourthBox.Text = strs[3];
            }
        }

        public byte[] GetByteArray()
        {
            byte[] userInput = new byte[4];

            userInput[0] = Convert.ToByte(firstBox.Text);
            userInput[1] = Convert.ToByte(secondBox.Text);
            userInput[2] = Convert.ToByte(thirdBox.Text);
            userInput[3] = Convert.ToByte(fourthBox.Text);

            return userInput;
        }

        private void jumpRight(TextBox rightNeighborBox, KeyEventArgs e)
        {
            rightNeighborBox.Focus();
            rightNeighborBox.CaretIndex = 0;
            e.Handled = true;
        }

        private void jumpLeft(TextBox leftNeighborBox, KeyEventArgs e)
        {
            leftNeighborBox.Focus();
            if (leftNeighborBox.Text != "")
            {
                leftNeighborBox.CaretIndex = leftNeighborBox.Text.Length;
            }
            e.Handled = true;
        }

        //checks for backspace, arrow and decimal key presses and jumps boxes if needed.
        //returns true when key was matched, false if not.
        private bool CheckJumpRight(TextBox currentBox, TextBox rightNeighborBox, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Right:
                    if (currentBox.CaretIndex == currentBox.Text.Length || currentBox.Text == "")
                    {
                        jumpRight(rightNeighborBox, e);
                    }
                    return true;
                case Key.OemPeriod:
                case Key.Decimal:
                case Key.Space:
                    jumpRight(rightNeighborBox, e);
                    rightNeighborBox.SelectAll();
                    return true;
                default:
                    return false;
            }
        }

        private void CheckJumpLeft(TextBox currentBox, TextBox leftNeighborBox, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Left:
                    if (currentBox.CaretIndex == 0 || currentBox.Text == "")
                    {
                        jumpLeft(leftNeighborBox, e);
                    }
                    return;
                case Key.Back:
                    if ((currentBox.CaretIndex == 0 || currentBox.Text == "") && currentBox.SelectionLength == 0)
                    {
                        jumpLeft(leftNeighborBox, e);
                    }
                    return;
                default:
                    return;
            }
        }

        //discards non digits, prepares IPMaskedBox for textchange.
        private void HandleTextInput(TextBox currentBox, TextBox rightNeighborBox, TextCompositionEventArgs e)
        {
            if (!char.IsDigit(Convert.ToChar(e.Text)))
            {
                e.Handled = true;
                SystemSounds.Beep.Play();
                return;
            }

            if (currentBox.Text.Length == 3 && currentBox.SelectionLength == 0)
            {
                e.Handled = true;
                SystemSounds.Beep.Play();
                if (!Equals(currentBox, fourthBox))
                {
                    rightNeighborBox.Focus();
                    rightNeighborBox.SelectAll();
                }
            }
        }

        //checks whether textbox content > 255 when 3 characters have been entered.
        //clears if > 255, switches to next textbox otherwise 
        private void HandleTextChange(TextBox currentBox, TextBox rightNeighborBox)
        {
            if (currentBox.Text.Length == 3)
            {
                try
                {
                    // ReSharper disable once UnusedVariable
                    var b = Convert.ToByte(currentBox.Text);
                }
                catch (Exception exception) when (exception is FormatException || exception is OverflowException)
                {
                    currentBox.Clear();
                    currentBox.Focus();
                    SystemSounds.Beep.Play();
                    MessageBox.Show(ErrorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }
                if (currentBox.CaretIndex != 2 && !Equals(currentBox, fourthBox))
                {
                    rightNeighborBox.CaretIndex = rightNeighborBox.Text.Length;
                    rightNeighborBox.SelectAll();
                    rightNeighborBox.Focus();
                }
            }
        }

        //jump right, left or stay. 
        private void firstByte_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            CheckJumpRight(firstBox, secondBox, e);
        }

        private void secondByte_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (CheckJumpRight(secondBox, thirdBox, e))
                return;

            CheckJumpLeft(secondBox, firstBox, e);
        }

        private void thirdByte_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (CheckJumpRight(thirdBox, fourthBox, e))
                return;

            CheckJumpLeft(thirdBox, secondBox, e);
        }

        private void fourthByte_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            CheckJumpLeft(fourthBox, thirdBox, e);

            if (e.Key == Key.Space)
            {
                SystemSounds.Beep.Play();
                e.Handled = true;
            }
        }

        //discards non digits, prepares IPMaskedBox for textchange.
        private void firstByte_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            HandleTextInput(firstBox, secondBox, e);
        }

        private void secondByte_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            HandleTextInput(secondBox, thirdBox, e);
        }

        private void thirdByte_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            HandleTextInput(thirdBox, fourthBox, e);
        }

        private void fourthByte_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            HandleTextInput(fourthBox, fourthBox, e); //pass fourthbyte twice because no right neighboring box.
        }

        //checks whether textbox content > 255 when 3 characters have been entered.
        //clears if > 255, switches to next textbox otherwise 
        private void firstByte_TextChanged(object sender, TextChangedEventArgs e)
        {
            HandleTextChange(firstBox, secondBox);
        }

        private void secondByte_TextChanged(object sender, TextChangedEventArgs e)
        {
            HandleTextChange(secondBox, thirdBox);
        }

        private void thirdByte_TextChanged(object sender, TextChangedEventArgs e)
        {
            HandleTextChange(thirdBox, fourthBox);
        }

        private void fourthByte_TextChanged(object sender, TextChangedEventArgs e)
        {
            HandleTextChange(fourthBox, fourthBox);
        }

        private void IPMaskedTextBox_OnLoaded(object sender, RoutedEventArgs e)
        {
            firstBox.Focus();
        }
    }
}
